/*
 * @Author: zhong_m
 * @Date: 2021-11-24 18:42:32
 * @LastEditTime: 2022-04-07 14:56:55
 * @LastEditors: zhong_m
 * @Description: 切换主题（仅对<style>标签内样式有效
 * @FilePath: \central-system\src\utils\theme.js
 */
import {theme} from '@/config'
import Vue from 'vue'
// 浅色组浅度列表
let alphaList = []
let styleFilterMap = new WeakMap()
function getCSSString(url) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest()
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        resolve(xhr.responseText.replace(/url\(["']?([\.\/\w\d_\-\#\?]+)["']?\)/gi,(...item) => {
          return `url("${url.substring(0, url.lastIndexOf('/')+1) + item[1]}")`
        }))
      }
    }
    xhr.open('GET', url) 
    xhr.send()
  })
}
// 获取主题色组
function getThemeCluster(theme, fix = 100) {
  const tintColor = (color, tint) => {
    let red = parseInt(color.slice(1, 3), 16)
    let green = parseInt(color.slice(3, 5), 16)
    let blue = parseInt(color.slice(5), 16)
    if (tint === 0) {
      // when primary color is in its rgb space
      return [red, green, blue].join(',')
    } else {
      red += Math.round(tint * (255 - red))
      green += Math.round(tint * (255 - green))
      blue += Math.round(tint * (255 - blue))
      red = (red > 15 ? '' : '0') + red.toString(16)
      green = (green > 15 ? '' : '0') + green.toString(16)
      blue = (blue > 15 ? '' : '0') + blue.toString(16)
      return `#${red}${green}${blue}`
    }
  }
  const shadeColor = (color, shade) => {
    let red = parseInt(color.slice(1, 3), 16)
    let green = parseInt(color.slice(3, 5), 16)
    let blue = parseInt(color.slice(5), 16)
    red = Math.round((1 - shade) * red)
    green = Math.round((1 - shade) * green)
    blue = Math.round((1 - shade) * blue)
    red = (red > 15 ? '' : '0') + red.toString(16)
    green = (green > 15 ? '' : '0') + green.toString(16)
    blue = (blue > 15 ? '' : '0') + blue.toString(16)
    return `#${red}${green}${blue}`
  }
  const clusters = [theme]
  // 已有浅色系列表直接使用
  if (alphaList.length) {
    alphaList.forEach(item => {
      clusters.push(tintColor(theme, item))
    })
  } else { // 用于获取所有透明度
    for (let i = 1; i < fix; i++) {
      clusters.push(tintColor(theme, Number((i / fix).toFixed(2))))
    }
  }
  clusters.push(shadeColor(theme, 0.1))
  return clusters
}
async function getStyles() {
  let styles = []
  await themeInit()
  if(Vue.prototype.$InQianKun) {
    styles = [].slice.call(
      document.querySelector(`#QKframe [data-name=${Vue.prototype.$appName}]`)
        .querySelectorAll('style'))
  }else {
    styles = [].slice.call(document.querySelectorAll('head style'))
  }
  return styles
}
// 获取使用的浅色系
async function getAlphaList(color) {
  let styles = await getStyles()
  let cluster = getThemeCluster(color, 100)
  let useColorAlpha = []
  styles.forEach(style => {
    let { innerText } = style
    let colorList = []
    if (typeof innerText !== 'string') return
    cluster.forEach((color, index) => {
      if (new RegExp(color, 'ig').test(innerText)) {
        useColorAlpha.push([cluster[index], index])
        colorList.push(color)
      }
    })
    colorList.length && styleFilterMap.set(style, colorList)
  })
  alphaList = []
  new Set(useColorAlpha.filter(item => item[1] > 0 && item[1] < 100)).forEach(item => {
    alphaList.push(item[1] / 100)
  })
}
/**
 *  将css文件处理为style
 */
export async function themeInit() {
  let linkList = []
  if(Vue.prototype.$InQianKun) {
    linkList = [].slice.call(
      document.querySelector(`#QKframe [data-name=${Vue.prototype.$appName}]`)
        .querySelectorAll('link[rel=stylesheet]'))
  }else {
    linkList = [].slice.call(document.querySelectorAll('head link[rel=stylesheet]'))
  }
  for (const item of linkList) {
    let text = await getCSSString(item.href)
    let styleTag = document.createElement('style')
    styleTag.innerText = text
    // insertAfter(item, styleTag)
    item.parentNode?.replaceChild(styleTag, item)
  }
}
/**
 * 更新style
 * @param {string} ntheme 新主题
 * @param {string} otheme 旧主题
 */
export async function updateStyle(ntheme, otheme = theme) {
  let styles = await getStyles()
  const orgb = [
    parseInt(otheme.slice(1, 3), 16),
    parseInt(otheme.slice(3, 5), 16),
    parseInt(otheme.slice(5), 16)
  ]
  const alphaToHex = alpha => {
    let hex = parseInt(alpha * 255)
      .toString(16)
      .toUpperCase()

    return hex.length > 1 ? hex : '0' + hex
  }
  if (!alphaList.length) {
    await getAlphaList(otheme)
  }
  const originalCluster = getThemeCluster(otheme)
  const themeCluster = getThemeCluster(ntheme)
  styles.forEach(style => {
    let { innerText } = style
    if (!innerText) return
    if(styleFilterMap.has(style)) {
      styleFilterMap.get(style).forEach((color, index) => {
        const ncolor = themeCluster[originalCluster.indexOf(color)]
        if (new RegExp(color, 'ig').test(innerText)) {
          innerText = innerText.replace(new RegExp(color, 'ig'), ncolor)
        }
        styleFilterMap.get(style)[index] = ncolor
      })
    }
    // 更新rgba类颜色
    if (new RegExp(`rgba\\(${orgb.join(',\\s?')}`, 'ig').test(innerText)) {
      innerText = innerText.replace(
        new RegExp(`rgba\\(${orgb.join(',\\s?')}(,(.+?))?\\)`, 'ig'),
        (...match) => {
          return `${ntheme}${alphaToHex(match[2])}`
        }
      )
    }
    style.innerText = innerText
  })
}
